package com.pince.permission;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;

import com.tbruyelle.rxpermissions3.RxPermissions;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import io.reactivex.rxjava3.functions.Consumer;

/**
 * 权限申请帮助类
 */
public final class PermissionHelper {
    private RxPermissions rxPermissions = null;
    private WeakReference<Context> contextWeakReference = null;

    public PermissionHelper(@NonNull FragmentActivity activity) {
        this.rxPermissions = new RxPermissions(activity);
        this.contextWeakReference = new WeakReference(activity);
    }

    public PermissionHelper(@NonNull Fragment fragment) {
        this.rxPermissions = new RxPermissions(fragment);
        this.contextWeakReference = new WeakReference(fragment.getActivity());
    }

    private static String getTipsStr(Context context, int resId) {
        if (context == null) {
            return "";
        }
        return String.format(context.getString(resId), getAppName(context));
    }

    private static String getAppName(Context context) {
        if (context == null) {
            return "";
        }
        return context.getString(context.getApplicationInfo().labelRes);
    }

    public void request(@NonNull final String permission, final PermissionCallback callback) {
        rxPermissions.request(permission).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean granted) throws Exception {
                if (!granted) {
                    if (callback != null) {
                        callback.onDenied(permission, getTipsStr(contextWeakReference.get(), R.string.permissions_denied_tips));
                    }
                } else {
                    if (callback != null) {
                        callback.onGranted();
                    }
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                if (callback != null) {
                    callback.onDenied(permission, getTipsStr(contextWeakReference.get(), R.string.permissions_denied_tips));
                }
            }
        });
    }

    public void request(@NonNull final String permission, @NonNull final String tips, final PermissionCallback callback) {
        rxPermissions.request(permission).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean granted) throws Exception {
                if (!granted) {
                    if (callback != null) {
                        callback.onDenied(permission, tips);
                    }
                } else {
                    if (callback != null) {
                        callback.onGranted();
                    }
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                if (callback != null) {
                    callback.onDenied(permission, tips);
                }
            }
        });
    }

    public void request(@NonNull Map<String, String> permissions, PermissionCallback callback) {
        Set<Map.Entry<String, String>> entrySet = permissions.entrySet();
        requestWithTips(entrySet.iterator(), callback);
    }

    public void requestWithTips(@NonNull final Iterator<Map.Entry<String, String>> iterator
            , final PermissionCallback callback) {
        if (!iterator.hasNext()) {
            if (callback != null) {
                callback.onGranted();
            }
            return;
        }

        final Map.Entry<String, String> permission = iterator.next();
        if (rxPermissions.isGranted(permission.getKey())) {
            requestWithTips(iterator, callback);
            return;
        }
        rxPermissions.request(permission.getKey()).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean granted) throws Exception {
                if (!granted) {
                    if (callback != null) {
                        callback.onDenied(permission.getKey(), permission.getValue());
                    }
                } else {
                    requestWithTips(iterator, callback);
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                if (callback != null) {
                    callback.onDenied(permission.getKey(), permission.getValue());
                }
            }
        });
    }

    public void request(@NonNull Set<String> permissions, PermissionCallback callback) {
        request(permissions.iterator(), callback);
    }

    public void request(@NonNull final Iterator<String> iterator, final PermissionCallback callback) {
        if (!iterator.hasNext()) {
            if (callback != null) {
                callback.onGranted();
            }
            return;
        }

        final String permission = iterator.next();
        if (rxPermissions.isGranted(permission)) {
            request(iterator, callback);
            return;
        }
        rxPermissions.request(permission).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean granted) throws Exception {
                if (!granted) {
                    if (callback != null) {
                        callback.onDenied(permission, getTipsStr(contextWeakReference.get(), R.string.permissions_denied_tips));
                    }
                } else {
                    request(iterator, callback);
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                if (callback != null) {
                    callback.onDenied(permission, getTipsStr(contextWeakReference.get(), R.string.permissions_denied_tips));
                }
            }
        });
    }
}
